
import {
  unstable_ImmediatePriority as ImmediatePriority,
  unstable_UserBlockingPriority as UserBlockingPriority,
  unstable_NormalPriority as NormalPriority,
  unstable_LowPriority as LowPriority,
  unstable_IdlePriority as IdlePriority,
  unstable_scheduleCallback as scheduleCallback,
  unstable_shouldYield as shouldYield,
  CallbackNode,
  unstable_getFirstCallbackNode as getFirstCallbackNode,
  unstable_cancelCallback as cancelCallback,

} from 'scheduler'

import "./style.css"


const button = document.querySelector("button")
const root = document.querySelector("#root")


type Priority = typeof ImmediatePriority 
| typeof UserBlockingPriority 
| typeof NormalPriority 
| typeof LowPriority 
| typeof IdlePriority


interface Work{
  count:number,
  priority:Priority,
}

const workList :Work[] = []

let prevPriority:Priority = IdlePriority

let curCallback:CallbackNode | null = null;

[LowPriority,NormalPriority,UserBlockingPriority,ImmediatePriority].forEach((priority : Priority) => {
    const button = document.createElement("button")
    button.innerText = ['','ImmediatePriority',
      'UserBlockingPriority',
      'NormalPriority',
      'LowPriority'
    ][priority];

    button.onclick = ()=>{
      workList.unshift({
        count:100,
        priority:priority
      })
      schedue()
    };

    root.appendChild(button)

});

function schedue() {
  const cbNode = getFirstCallbackNode()
  const curWork = workList.sort((w1,w2)=>w1.priority-w2.priority)[0]
  //todo 策略逻辑

  if(!curWork){
    curCallback = null
    cbNode && cancelCallback(cbNode)
    return
  }

  const {priority:curPriority} = curWork
  if(curPriority === prevPriority)return

  //更高优先级的work
  cbNode && cancelCallback(cbNode)

  curCallback = scheduleCallback(curPriority,perform.bind(null,curWork))

}

function perform(work:Work,didTimeout?:boolean) {

  /**
   * 1.work.priority
   * 2.饥饿问题
   * 3.时间切片
   */
  const needSync = work.priority === ImmediatePriority || didTimeout
  while( (needSync|| !shouldYield()) && work.count){
    work.count-- 
    insertSpan(work.priority+"")
  }
  //中断执行 执行完
  prevPriority = work.priority
  if(!work.count){
    const workIndex = workList.indexOf(work)
    workList.splice(workIndex,1)
    prevPriority = IdlePriority
  }
  const prevCallback = curCallback;
  schedue()
  const newCallback = curCallback
  if(newCallback && prevCallback === newCallback){
    return perform.bind(null,work)
  }
}

function insertSpan(content) {
  const span = document.createElement("span")
  span.innerText = content
  span.className = `pri-${content}`
  doSomeBuzyWork(10000000)

  root.appendChild(span)
}

function  doSomeBuzyWork(len:number) {
  let result = 0;
  while (len--) {
    result += len;
  }
}